﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using OverStore.Runtime.PersistenceServiceProvider;
using OverStore.Runtime.Storage;
using OverStore.Configuration.ObjectRepository.Mapping;

namespace OverStore.Configuration.Builder.Fluent
{
    /// <summary>
    /// Specifies get object data function.
    /// </summary>
    /// <typeparam name="TInstance">The type of the instance.</typeparam>
    /// <typeparam name="TIdentifier">The type of the identifier.</typeparam>
    /// <typeparam name="TPrevStep">The type of the prev step.</typeparam>
    public class DelegateMapperGetObjectDataStep<TInstance, TIdentifier, TPrevStep>
        where TInstance : class
    {
        private readonly DelegateMapperConfiguration<TInstance> _Mapper;
        private readonly Func<DelegateMapperConfiguration<TInstance>, TPrevStep> _CompleteFunc;

        /// <summary>
        /// Initializes a new instance of the <see cref="DelegateMapperGetObjectDataStep&lt;TInstance, TIdentifier, TPrevStep&gt;"/> class.
        /// </summary>
        /// <param name="mapper">The mapper.</param>
        /// <param name="completeFunc">The complete func.</param>
        public DelegateMapperGetObjectDataStep(
            DelegateMapperConfiguration<TInstance> mapper,
            Func<DelegateMapperConfiguration<TInstance>, TPrevStep> completeFunc)
        {
            if (Object.ReferenceEquals(mapper, null))
                throw new ArgumentNullException("mapper");
            if (Object.ReferenceEquals(completeFunc, null))
                throw new ArgumentNullException("completeFunc");

            _Mapper = mapper;
            _CompleteFunc = completeFunc;
        }

        /// <summary>
        /// Specifies function for get object data.
        /// </summary>
        public DelegateMapperApplyObjectDataStep<TInstance, TIdentifier, TPrevStep> GetObjectDataUsing(
            Func<TInstance, string, IRegistry, object> getObjectDataFunc)
        {
            if (Object.ReferenceEquals(getObjectDataFunc, null))
                throw new ArgumentNullException("getObjectDataFunc");
            _Mapper.GetObjectDataFunction = getObjectDataFunc;
            return new DelegateMapperApplyObjectDataStep<TInstance, TIdentifier, TPrevStep>(_Mapper, _CompleteFunc);
        }
    }

    /// <summary>
    /// Specifies apply object data function.
    /// </summary>
    /// <typeparam name="TInstance">The type of the instance.</typeparam>
    /// <typeparam name="TIdentifier">The type of the identifier.</typeparam>
    /// <typeparam name="TPrevStep">The type of the prev step.</typeparam>
    public class DelegateMapperApplyObjectDataStep<TInstance, TIdentifier, TPrevStep>
        where TInstance : class
    {
        private readonly DelegateMapperConfiguration<TInstance> _Mapper;
        private readonly Func<DelegateMapperConfiguration<TInstance>, TPrevStep> _CompleteFunc;

        /// <summary>
        /// Initializes a new instance of the <see cref="DelegateMapperApplyObjectDataStep{TInstance,TIdentifier,TPrevStep}"/> class.
        /// </summary>
        /// <param name="mapper">The mapper.</param>
        /// <param name="completedFunct">The completed funct.</param>
        public DelegateMapperApplyObjectDataStep(
            DelegateMapperConfiguration<TInstance> mapper,
            Func<DelegateMapperConfiguration<TInstance>, TPrevStep> completedFunct)
        {
            if (Object.ReferenceEquals(mapper, null))
                throw new ArgumentNullException("mapper");
            if (Object.ReferenceEquals(completedFunct, null))
                throw new ArgumentNullException("completedFunct");
            _Mapper = mapper;
            _CompleteFunc = completedFunct;
        }

        /// <summary>
        /// Specifies the function applies object data.
        /// </summary>
        public TPrevStep ApplyDataUsing(Action<TypedRecord, TInstance, IRegistry> applyObjectData)
        {
            if (Object.ReferenceEquals(applyObjectData, null))
                throw new ArgumentNullException("applyObjectData");
            _Mapper.ApplyObjectDataFunction = applyObjectData;
            return _CompleteFunc(_Mapper);
        }
    }
}
